package com.fattyCorps.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fattyCorps.cache.PlayerCache;
import com.fattyCorps.config.gameConfig.GlobalConfig;
import com.fattyCorps.exception.gameException.CreatePlayerErrorException;
import com.fattyCorps.mapper.PlayerMapper;
import com.fattyCorps.mgr.event.EEvent;
import com.fattyCorps.mgr.event.EventMgr;
import com.fattyCorps.obj.cache.PlayerInfo;
import com.fattyCorps.obj.db.DtoPlayer;
import com.fattyCorps.obj.db.PlayerData;
import com.fattyCorps.obj.msg.SRet;
import com.fattyCorps.obj.msg.server.player.SGetInfo;
import com.fattyCorps.utils.DateUtils;
import com.fattyCorps.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;

@Service
@Slf4j
public class PlayerService {

    @Autowired
    PlayerMapper playerMapper;

    @Autowired
    PlayerCache playerCache;

    @Autowired
    HeroService heroService;

    @Autowired
    ItemService itemService;

    @Autowired
    MailService mailService;

    @Autowired
    GlobalConfig globalConfig;

    @Autowired
    EventMgr eventMgr;

    public int createPlayer(Integer accountId) {
        Integer initHead = globalConfig.getIntValue(GlobalConfig.PLAYER_INIT_HEAD);
        Integer initLv = globalConfig.getIntValue(GlobalConfig.PLAYER_INIT_LV);
        Integer initCoin = globalConfig.getIntValue(GlobalConfig.PLAYER_INIT_COIN);
        Integer initGuanqia = globalConfig.getIntValue(GlobalConfig.PLAYER_INIT_GUANQIA);

        PlayerInfo playerInfo = new PlayerInfo();
        playerInfo.setNickname("acc" + accountId);
        playerInfo.setAccountId(accountId);

        playerInfo.setPlayerData(new PlayerData());
        playerInfo.getPlayerData().setHead(initHead);
        playerInfo.getPlayerData().setLv(initLv);
        playerInfo.getPlayerData().setCoin(initCoin);
        playerInfo.getPlayerData().setGuanqia(initGuanqia);
        playerInfo.getPlayerData().setGlobalMailId(0);

        SimpleDateFormat df = new SimpleDateFormat(DateUtils.YYYY_MM_DD_HH_MM_SS);
        String initTimeStr = df.format(Integer.valueOf(0));
        playerInfo.getPlayerData().setLastFreeLotteryTime(initTimeStr);

        // 派发消息，其他模块相应，处理创建初始化工作
        eventMgr.sendEvent(EEvent.EVENT_ON_PLAYER_CREATE, playerInfo);

        DtoPlayer dto = playerInfo.getDto();
        try {
            playerMapper.insert(dto);
        } catch (Exception e) {
            log.error("getInfo error: accountId" + accountId);
            e.printStackTrace();
            throw new CreatePlayerErrorException();
        }

        return dto.getId();
    }

    // 获取角色信息
    public SRet getInfo(Integer accountId) {
        QueryWrapper<DtoPlayer> wrapper = new QueryWrapper<>();
        wrapper.eq("account_id", accountId);
        DtoPlayer dtoPlayer = playerMapper.selectOne(wrapper);

        int playerId = dtoPlayer == null ? createPlayer(accountId) : dtoPlayer.getId();

        // 将角色信息加入cache
        initCache(playerId);
        PlayerInfo playerInfo = playerCache.getPlayerInfo(playerId);
//        onPlayerLogin(playerInfo);
        eventMgr.sendEvent(EEvent.EVENT_ON_PLAYER_LOGIN, playerInfo);

        String playerToken = JwtUtil.createPlayerToken(playerId);

        // 向客户端返回角色信息
        SGetInfo sGetInfo = new SGetInfo();
        sGetInfo.setNickname(playerInfo.getNickname());
        sGetInfo.setHead(playerInfo.getPlayerData().getHead());
        sGetInfo.setLv(playerInfo.getPlayerData().getLv());
        sGetInfo.setCoin(playerInfo.getPlayerData().getCoin());
        sGetInfo.setGuanqia(playerInfo.getPlayerData().getGuanqia());
        sGetInfo.setNewToken(playerToken);

        return SRet.success(sGetInfo);
    }

    // 处理心跳
    public void procHeartBeat(Integer playerId) {
        PlayerInfo playerInfo = playerCache.getPlayerInfo(playerId);
        long curTime = System.currentTimeMillis();
        playerInfo.setLastHeartBeatTime(curTime);
    }

    // 增加或删除元宝
    // return: 返回操作结果
    public boolean addCoin(Integer playerId, Integer coin) {
        PlayerInfo playerInfo = playerCache.getPlayerInfo(playerId);
        Integer curCoin = playerInfo.getPlayerData().getCoin();

        int a = 1/0;

        if (coin < 0) {
            // 扣钱
            if (curCoin < -coin) {
                // 元宝不足
                return false;
            }
        } else if (coin == 0) {
            return true;
        }

        Integer newCoin = curCoin + coin;
        playerInfo.getPlayerData().setCoin(newCoin);

        return true;
    }

    public Integer getCoin(Integer playerId) {
        return playerCache.getPlayerInfo(playerId).getPlayerData().getCoin();
    }

    // 加载数据库信息到缓存
    private void initCache(int playerId) {
        // 加载用户基础信息到缓存
        PlayerInfo playerInfo = playerCache.getPlayerInfo(playerId, false);
        if (playerInfo != null) {
            return;
        }

        DtoPlayer dtoPlayer = playerMapper.selectById(playerId);
        playerInfo = new PlayerInfo();
        playerInfo.loadFromDto(dtoPlayer);

        // 初始化心跳时间
        playerInfo.setLastHeartBeatTime(System.currentTimeMillis());

        playerCache.addPlayerInfo(playerInfo);
    }

    public void passGuanQia(Integer playerId) {
        PlayerInfo playerInfo = playerCache.getPlayerInfo(playerId);

        // 先写个简单的，后续这里要做正确性判断
        playerInfo.getPlayerData().setGuanqia(playerInfo.getPlayerData().getGuanqia() + 1);


        eventMgr.sendEvent(EEvent.EVENT_UPDATE_GUANQIA, playerId, playerInfo.getPlayerData().getGuanqia());

        // 更新等级
        lvUp(playerId);
    }

    public void lvUp(Integer playerId) {
        PlayerInfo playerInfo = playerCache.getPlayerInfo(playerId);
        playerInfo.getPlayerData().setLv(playerInfo.getPlayerData().getLv() + 1);

        // 更新排行榜
        eventMgr.sendEvent(EEvent.EVENT_UPDATE_LV, playerId, playerInfo.getPlayerData().getLv());
    }
}
